﻿#pragma once

#include <cstdio>
#include <cstdlib>
#include <cstring> // linux C style memset should use string.h
#include <cstdarg>
#include <ctime>
#include <cassert>
#include <cmath>
#include <memory>
#include <climits>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <functional>
#include <exception>

#include <cstdbool>
#include <cstdint>
#include <cfloat>

#ifdef _WIN32
#include <io.h>
#include <direct.h>
#include <windows.h>
#include <windef.h>
#pragma comment(lib,"Winmm.lib")	//For timeSetEvent
#else
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/time.h>
#endif

#ifdef _MSC_VER
#pragma warning(disable: 4996) 
//#pragma warning(disable: 2036) 
#endif

typedef enum class ReturnStateEnum
{
	SUCCESS = 0,
	RTN_WARN = 1,	// 警告,继续执行
	RTN_ERR = 2,	// 错误, 抛出异常并退出此函数
	RTN_FATAL = 3	// 失败, 终止程序
} E_ffState;
#define ffChkErr(val) do{\
	E_ffState val_hold = val; \
	if(val_hold == E_ffState::RTN_ERR) return val;\
	if(val_hold == E_ffState::RTN_FATAL) exit(EXIT_FAILURE);\
}while(0)

#if defined(__GNUC__)
#if defined(__i386__)
#define FF_STDCALL __attribute__((stdcall))
#else
#define FF_STDCALL
#endif
#else
#define FF_STDCALL __stdcall
#endif
#define FF_API FF_STDCALL

namespace feifei
{
#pragma region BASIC

#ifdef _WIN32
#define	DIR_SPT ('\\')
#else
#define	DIR_SPT ('/')
#endif

	typedef void(*PVoidFunc)();
	typedef E_ffState(*PRetFunc)();
	typedef E_ffState(*PRetFunc2)(void* param);

	extern void exec_cmd(std::string cmd);
	extern bool is_path_exist(std::string path);
	extern E_ffState ensure_path(std::string path);

	extern std::string wstr_to_str(const std::wstring& wstr);
	extern std::wstring str_to_wstr(std::string str);

	extern std::string get_curr_path(); 
	extern std::string get_work_path();
	extern std::string get_debug_path();
	extern std::string get_log_path();
	extern E_ffState set_work_path(std::string path);
	extern void release_work_path();

	extern std::string get_file_path(std::string fileName);
	extern std::string get_file_name(std::string fileName);

	extern size_t read_bin_file(std::string file_name, char* binary);
	extern E_ffState write_to_bin_file(std::string file_name, std::vector<char>* binary);
	extern E_ffState write_to_txt_file(std::string file_name, std::string str);

#pragma endregion

	/************************************************************************/
	/* arithmetic															*/
	/************************************************************************/
#pragma region ARITH

#define	MIN_FP32_ERR		(1e-6)
#define MAX_16BIT_UINT		(65535)
	const double PI = acos(-1.0);
	const float PI_FP32 = acosf(-1.0f);
//#define PI					(3.1415926535897932384626433832795028841971)		// 定义圆周率值
//#define PI_FP32				(3.1415926535897932384626433832795028841971f)		// 定义圆周率值

#ifndef max
#define max(a,b)            (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b)            (((a) < (b)) ? (a) : (b))
#endif

#define	c2s(c)				std::string(c)
#define	s2c(s)				s.c_str()
#define	d2s(d)				std::to_string(d)
#define	f2s(f)				std::to_string((float)f)
#define d2c(d)				(char*)(s2c(d2s(d)))
#define	d2hs(d)				std::string("0x0+"+std::to_string(d))
#define	c2hs(c)				std::string("0x0+"+c2s(c))

	inline int nextpow2(int n)
	{
		int base = 1;
		for (int i = 0; i < 32; i++)
		{
			base = 1 << i;

			if (n <= base)
				break;
		}
		return base;
	}
	inline int log2Int(int value)
	{
		int log2 = 0;
		while (value > 1) { value = value / 2; log2++; }
		return log2;
	}

	inline unsigned int f32_as_u32(float f) { union { float f; unsigned int u; } v; v.f = f; return v.u; }
	inline float u32_as_f32(unsigned int u) { union { float f; unsigned int u; } v; v.u = u; return v.f; }
	inline int clamp_int(int i, int l, int h) { return min(max(i, l), h); }
	inline short cvtFP32toFP16(float f)
	{
		uint32_t * p = (uint32_t*)&f;

		unsigned int sig = (*p >> 16) & 0x8000;
		int exp = ((*p >> 23) & 0xff) - 127 + 15;
		unsigned int m = ((*p >> 11) & 0xffe) | ((*p & 0xfff) != 0);
		unsigned int i = 0x7c00 | (m != 0 ? 0x0200 : 0);
		unsigned int n = (exp << 12) | m;

		int b = clamp_int(1 - exp, 0, 13);
		unsigned int d = (0x1000 | m) >> b;
		d |= (d << b) != (0x1000 | m);
		unsigned int v = exp < 1 ? d : n;

		v = (v >> 2) + (((v & 0x7) == 3) | ((v & 0x7) > 5));
		v = exp > 30 ? 0x7c00 : v;
		v = exp == 143 ? i : v;

		short r = sig | v;
		return r;
	}
	inline float cvtFP16toFP32(unsigned short a)
	{
		unsigned int u = ((a << 13) + 0x70000000U) & 0x8fffe000U;
		unsigned int v = f32_as_u32(u32_as_f32(u) * powf(1.0f, 112)) + 0x38000000U;
		u = (a & 0x7fff) != 0 ? v : u;
		return u32_as_f32(u) * powf(1.0f, -112);
	}
	inline short cvtFP32toBF16(float in)
	{
		return (*(uint32_t*)(&in) >> 16);
	}
	inline float cvtBF16toFP32(unsigned short in)
	{
		uint32_t tmp = in << 16;
		return *(float*)(&tmp);
	}

#define isPow2(value)  ((value & (value - 1)) == 0)
#define modMask(value) (value - 1)
#define divCeil(a,b)	((a + b - 1) / b)

#define randInt10(a,b) ((rand() % (b-a)) + a)   	// [a,b)
#define randInt11(a,b) ((rand() % (b-a+1)) + a) 	// [a,b]
#define randInt01(a,b) ((rand() % (b-a)) + a + 1)	// (a,b]
	
	template <typename T>
	struct cplx
	{
		T x, y;

		cplx() :x(0), y(0) {}
		cplx(const T& d) :x(d), y(d) {}
		cplx(const T& _x, const T& _y) :x(_x), y(_y) {}

		cplx conj()const { return cplx(x, -y); }
		T abs()const { return (T)sqrt(x * x + y * y); }

		friend bool operator == (const cplx& a, const cplx& b) { return(a.x == b.x && a.y == b.y); }

		friend cplx operator+(const cplx& a, const T& b) { return cplx(a.x + b, a.y + b); }
		friend cplx operator-(const cplx& a, const T& b) { return cplx(a.x - b, a.y - b); }
		friend cplx operator*(const cplx& a, const T& b) { return cplx(a.x * b, a.y * b); }
		friend cplx operator/(const cplx& a, const T& b) { return cplx(a.x / b, a.y / b); }

		void operator+=(const T& b) { x += b; y += b; }
		void operator-=(const T& b) { x -= b; y -= b; }
		void operator*=(const T& b) { x *= b; y *= b; }
		void operator/=(const T& b) { x /= b; y /= b; }

		friend cplx operator+(const cplx& a, const cplx& b) { return cplx(a.x + b.x, a.y + b.y); }
		friend cplx operator-(const cplx& a, const cplx& b) { return cplx(a.x - b.x, a.y - b.y); }
		friend cplx operator*(const cplx& a, const cplx& b) { return cplx(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); }
		friend cplx operator/(const cplx& a, const cplx& b) { return a * b.conj() / (b.x * b.x + b.y * b.y); }

		cplx operator+=(const cplx& b) { return cplx(x + b.x, y + b.y); }
		cplx operator-=(const cplx& b) { return cplx(x - b.x, y - b.y); }
		cplx operator*=(const cplx& b) { return cplx(x * b.x - y * b.y, x * b.y + y * b.x); }
		cplx operator/=(const cplx& b) { return cplx(x, y) * b.conj() / (b.x * b.x + b.y * b.y); }
	};

#pragma endregion

	/************************************************************************/
	/* file and log															*/
	/************************************************************************/
#pragma region LOG

#define INFO(fmt,...)		PrintInfo(fmt,##__VA_ARGS__)
#define	LOG(fmt,...)		PrintLog(fmt,##__VA_ARGS__)
#define WARN(fmt,...)		PrintWarning(__FILE__,__LINE__,fmt,##__VA_ARGS__)
#define ERR(fmt,...)		do{PrintError(__FILE__,__LINE__,fmt,##__VA_ARGS__);return E_ffState::RTN_ERR;}while(0)
#define FATAL(fmt,...)		PrintFatal(__FILE__,__LINE__,fmt,##__VA_ARGS__)
	
	std::string fmtTime(double sec);
	std::string fmtFreq(uint64_t freqHz);
	std::string fmtSize(size_t szByte);

	// 输出分隔符
	void PrintSeperator(const char c, FILE* of = stdout);//std::ostream* sm = &std::cout
	void PrintHeader(std::string header, const char c = 0, FILE* of = stdout);
	// cout输出
	void PrintInfo(const char* format, ...);
	void PrintInfo(std::string msg, ...);
	// 带时间戳的clog输出
	void PrintLog(const char* format, ...);
	void PrintLog(std::string msg, ...);
	// 带时间戳和错误位置的clog输出
	void PrintWarning(const char* file, int line, const char* format, ...);
	void PrintWarning(const char* file, int line, std::string msg, ...);
	// 带时间戳和错误位置并返回错误的cerr输出
	E_ffState PrintError(const char* file, int line, const char* format, ...);
	E_ffState PrintError(const char* file, int line, std::string msg, ...);
	// 带时间戳和错误位置并终止程序的cerr输出
	void PrintFatal(const char* file, int line, const char* format, ...);
	void PrintFatal(const char* file, int line, std::string msg, ...);

	inline void print_value(float v, int fmtLen, FILE* of)
	{
		std::string fmtstr = (fmtLen == 0) ? "%f, " : ("%." + std::to_string(fmtLen) + "f, ");
		fprintf(of, fmtstr.c_str(), v);
	}
	inline void print_value(double v, int fmtLen, FILE* of)
	{
		std::string fmtstr = (fmtLen == 0) ? "%f, " : ("%." + std::to_string(fmtLen) + "f, ");
		fprintf(of, fmtstr.c_str(), v);
	}
	inline void print_value(int32_t v, int fmtLen, FILE* of)
	{
		std::string fmtstr = (fmtLen == 0) ? "%d, " : ("%0" + std::to_string(fmtLen) + "d, ");
		fprintf(of, fmtstr.c_str(), v);
	}
	inline void print_value(uint32_t v, int fmtLen, FILE* of) 
	{
		std::string fmtstr = (fmtLen == 0) ? "%ud, " : ("%0" + std::to_string(fmtLen) + "ud, ");
		fprintf(of, fmtstr.c_str(), v);
	}
	inline void print_value(cplx<float> v, int fmtLen, FILE* of)
	{
		std::string fmtstr = (fmtLen == 0) ? "%f" : ("%." + std::to_string(fmtLen) + "f");
		fprintf(of, "<");
		fprintf(of, fmtstr.c_str(), v.x);
		fprintf(of, ", ");
		fprintf(of, fmtstr.c_str(), v.y);
		fprintf(of, "> ");
	}
	inline void print_value(cplx<double> v, int fmtLen, FILE* of)
	{
		std::string fmtstr = (fmtLen == 0) ? "%f" : ("%." + std::to_string(fmtLen) + "f");
		fprintf(of, "<");
		fprintf(of, fmtstr.c_str(), v.x);
		fprintf(of, ", ");
		fprintf(of, fmtstr.c_str(), v.y);
		fprintf(of, "> ");
	}
	template<typename T>inline void print_hex(T v, int fmtLen, FILE* of)
	{
		std::string fmtstr = (fmtLen == 0) ? "0x%X, " : ("0x%0" + std::to_string(fmtLen) + "X, ");
		fprintf(of, fmtstr.c_str(), v);
	}
	inline void print_hex(cplx<float> v, int fmtLen, FILE* of)
	{
		std::string fmtstr = (fmtLen == 0) ? "0x%X" : ("0x%0" + std::to_string(fmtLen) + "X");
		fprintf(of, "<");
		fprintf(of, fmtstr.c_str(), v.x);
		fprintf(of, ", ");
		fprintf(of, fmtstr.c_str(), v.y);
		fprintf(of, "> ");
	}
	inline void print_hex(cplx<double> v, int fmtLen, FILE* of)
	{
		std::string fmtstr = (fmtLen == 0) ? "0x%X" : ("0x%0" + std::to_string(fmtLen) + "X");
		fprintf(of, "<");
		fprintf(of, fmtstr.c_str(), v.x);
		fprintf(of, ", ");
		fprintf(of, fmtstr.c_str(), v.y);
		fprintf(of, "> ");
	}

	/// <summary>
	/// 打印输出数组
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="pData">数组地址</param>
	/// <param name="len">输出元素的个数</param>
	/// <param name="name">输出数据的名字(默认为空)</param>
	/// <param name="startIdx">起始下标(默认为0)</param>
	/// <param name="isHex">是否以十六进制输出(默认为否)</param>
	/// <param name="numPerRow">每行输出的元素个数(默认为8个)</param>
	/// <param name="fmtLen">输出格式(默认为2位)</param>
	/// <param name="of">输出流(默认为标准输出)</param>
	template<typename T> void LogData(const T* pData, const size_t len, 
		std::string name = "", 
		uint64_t startIdx = 0, bool isHex = false,
		int numPerRow = 8,int fmtLen = 2,
		FILE* of = stdout)
	{
		if (pData == NULL)
		{
			printf("null data! \r\n");
			return;
		}

		fprintf(of, "\r\n------------------ %s ------------------\r\n", name.c_str());

		for (size_t i = startIdx; i < startIdx + len; i++)
		{
			if (i % numPerRow == 0)
				fprintf(of, "[%03zu~%03zu]: ", i, i + numPerRow - 1);

			if (isHex == true)
			{
				std::string fmtstr = (fmtLen == 0) ? "0x%X, " : ("0x%0" + std::to_string(fmtLen) + "X, ");
				print_hex(*(pData + i), fmtLen, of);
			}
			else
			{
				print_value(*(pData + i), fmtLen, of);
			}

			if ((i + 1) % numPerRow == 0)
				fprintf(of, "\n");
		}

		fprintf(of, "\n");
	}
	/// <summary>
	/// 以ASCII格式打印数据到文件
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="pData">数据地址</param>
	/// <param name="len">打印元素的个数</param>
	/// <param name="file_name">文件名(需要文件全路径和拓展名)</param>
	/// <param name="isAppend">是否追加文件(默认不追加，创建新文件)</param>
	/// <param name="startIdx">起始下表(默认为0)</param>
	/// <param name="isHex">是否以十六进制格式输出(默认为否)</param>
	/// <param name="numPerRow">每行输出的元素个数(默认为8个)</param>
	/// <param name="fmtLen">输出格式(默认为4位)</param>
	template<typename T> void DumpData(const T* pData, const size_t len,
		std::string full_file_name, bool isAppend = false,
		uint64_t startIdx = 0, bool isHex = false,
		int numPerRow = 8, int fmtLen = 4)
	{
		FILE* fp;
		if (isAppend)	fp = fopen(full_file_name.c_str(), "a+");
		else			fp = fopen(full_file_name.c_str(), "w+");
		LogData<T>(pData, len, "", startIdx, isHex, numPerRow, fmtLen, fp);
		fclose(fp);
	}
	/// <summary>
	/// 以二进制个数保存数据到文件
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="addr">数据地址</param>
	/// <param name="len">保存元素的个数</param>
	/// <param name="file_name">文件名(需要文件全路径和拓展名)</param>
	/// <param name="isAppend">是否追加文件(默认不追加，创建新文件)</param>
	/// <param name="startIdx">起始下表(默认为0)</param>
	template<typename T> E_ffState DumpMem(const T* addr, const size_t len, 
		std::string full_file_name, bool isAppend = false,
		uint64_t startIdx = 0)
	{
		std::ofstream fout;
		if (isAppend)
			fout.open(full_file_name.c_str(), std::ios::out | std::ios::binary | std::ios::ate | std::ios::app);
		else
			fout.open(full_file_name.c_str(), std::ios::out | std::ios::binary);

		if (!fout.is_open())
		{
			WARN("can't open save file: %s\n", full_file_name.c_str());
			return E_ffState::RTN_ERR;
		}
		fout.write((char*)addr + startIdx * sizeof(T), len * sizeof(T));
		fout.close();
		return E_ffState::SUCCESS;
	}
	/// <summary>
	/// 从二进制文件读取数据
	/// </summary>
	/// <param name="addr">读取到的地址,如果希望该函数分配,需要将 *addr = NULL !!!!! </param>
	/// <param name="file_name">文件名(需要文件全路径和拓展名)</param>
	/// <param name="skip_size">跳过的字节数</param>
	/// <param name="load_size">读取的字节数</param>
	/// <returns>返回读取的字节数</returns>
	static size_t LoadMem(void** addr, std::string full_file_name, size_t skip_size = 0, size_t load_size = 0)
	{
		std::ifstream fin(full_file_name.c_str(), std::ios::in | std::ios::binary);
		if (!fin.is_open())
		{
			WARN("can't open bin file: " + full_file_name);
			return 0;
		}

		size_t fullSize, leftSize;
		fin.seekg(0, std::ios::end);
		fullSize = (size_t)fin.tellg();
		if (skip_size >= fullSize)
		{
			WARN("read bin file over bias: " + fmtSize(skip_size));
			return 0;
		}

		leftSize = fullSize - skip_size;

		if ((leftSize < load_size) || (load_size == 0))
		{
			load_size = leftSize;
			LOG("read to end of file.");
		}
		if (*addr == NULL)
			*addr = malloc(load_size);

		fin.seekg(skip_size, std::ios::beg);
		fin.read((char*)(*addr), load_size);

		fin.close();
		return load_size;
	}

	class LogFile
	{
	public:
		LogFile(std::string file_name = "", bool isNewFile = true);
		~LogFile();
		void Log(const char * format, ...);
		void Log(std::string msg, ...);
		void Info(const char* format, ...);
		void Info(std::string msg, ...);
		void PrintSeperator(const char c);
		void PrintHeader(std::string header, const char c);

	protected:
		void ensureLogDir();
		std::string log_dir;
		std::string file_name;
		std::ofstream * fstream;
		char * PrintBuffer;
	};

	extern E_ffState CreateDefaultLogFile();
	extern void ReleaseDefaultLogFile();
	extern LogFile* GetDefaultLogFile();
	extern LogFile* gLogFile;
#define	fLOG(fmt,...)		do{if(feifei::gLogFile!=nullptr) feifei::gLogFile->Log(fmt,##__VA_ARGS__);}while(0)
#define fINFO(fmt,...)		do{if(feifei::gLogFile!=nullptr) feifei::gLogFile->Info(fmt,##__VA_ARGS__);}while(0)

#pragma endregion

	/************************************************************************/
	/* timer																*/
	/************************************************************************/
#pragma region TIMER

#ifdef _WIN32	
	inline void ffSleepSec(int sec) { Sleep(sec * 1000); }
	inline void ffSleepSec(double sec) { Sleep((unsigned int)(sec * 1000)); }
	inline void ffSleepMilliSec(int ms) { Sleep(ms); }
	inline void ffSleepMilliSec(double ms) { Sleep((unsigned int)ms); }
#else
	inline void ffSleepSec(int sec) { sleep(sec); }
	inline void ffSleepSec(double sec) { usleep((unsigned int)(sec * 1000 * 1000)); }
	inline void ffSleepMilliSec(int ms) { usleep(ms * 1000); }
	inline void ffSleepMilliSec(double ms) { usleep((unsigned int)(ms * 1000)); }
#endif

#ifdef _WIN32
	class ffTimer
	{
	protected:
		timespec startTime;
		timespec stopTime;

	public:
		void Restart();
		void Stop();

		double ElapsedMilliSec = 0;
		double ElapsedNanoSec = 0;

	protected:
		LARGE_INTEGER cpuFreqHz;
		LARGE_INTEGER startCnt;
		LARGE_INTEGER stopCnt;
	};
#else
	class ffTimer
	{
	protected:
		timespec startTime;
		timespec stopTime;

	public:
		void Restart();
		void Stop();

		double ElapsedMilliSec = 0;
		double ElapsedNanoSec = 0;
	};
#endif

#pragma endregion

	/************************************************************************/
	/* data base															*/
	/************************************************************************/
#pragma region DATA_BASE

	/* NEED TODO: 需要存储的数据结构 */
	typedef struct SaveDataType
	{
		int a;
		float b;
		char c;
		double d;
	} T_SaveData;

	class Database
	{
	public:
		Database(std::string db_file);

		void LoadDbFile();
		void ResaveDbFile();
		void SaveRcd(T_SaveData rcd);
		void AppendRcd(T_SaveData rcd);

		std::map<std::string, T_SaveData> SaveDataMap;
		std::string GenKeyStr(T_SaveData rcd);
		T_SaveData Find(std::string key);

	private:
		std::string dbDirPath;
		std::string dbFileName;

		char checkSum(std::string key, T_SaveData rcd);
	};

#pragma endregion

	/************************************************************************/
	/* command line parameter												*/
	/************************************************************************/
#pragma region CMD_IF

	/* DEMO NEED TODO: 
	typedef enum ArgIdEnum
	{
		CMD_ARG_HELP,
		CMD_ARG_TEST
	} E_ArgId;

	void main()
	{
		CmdArgs* ca = CmdArgs::GetCmdArgs();
		ca->AddOneArg(CMD_ARG_HELP, CmdArgs::E_ValueType::String, "help", 'h', "help", "help infomation\n");
		ca->AddOneArg(CMD_ARG_TEST, CmdArgs::E_ValueType::Int, "0", 't', "test", "test enviroment and simu parameters\n");
		ca->PaserCmdArgs(argc, argv);
	}*/
	class CmdArgs
	{
	public:
		typedef enum DataTypeEnum
		{
			Int,
			Float,
			String
		} E_ValueType;
		typedef struct CmdArgType
		{
			uint32_t id;
			std::string longName;
			char shortName;
			std::string value;
			int iValue;
			double fValue;
			std::string sValue;
			E_ValueType type;
			std::string helpText;
		} T_CmdArg;

		CmdArgs(int argc, char* argv[]); // not ready for now !

		void * GetOneArg(uint32_t id);
		void AddOneArg(uint32_t id, E_ValueType dType, std::string defaultVal, char sName = '\0', std::string lName = "", std::string tHelp = "");
		void PaserCmdArgs(int argc, char* argv[]);

		static CmdArgs * GetCmdArgs();
		std::string ExecutePath() { return executePath; }

	private:
		CmdArgs();

		static CmdArgs * pCmdArgs;
		int argsNum = 0;
		std::map<uint32_t, T_CmdArg*> * argsMap;
		std::string executePath; 
		int _argc;
		char** _argv;

		void helpText();
		void setOneArg(char sName, char* pvalue);
		void setOneArg(std::string lName, char* pvalue);
		void setOneArgValue(T_CmdArg* arg, char* pvalue);
		void setOneArgValue(T_CmdArg* arg, std::string value);
		void* getOneArgValue(T_CmdArg* arg);
	};

#pragma endregion

	/************************************************************************/
	/* task pool															*/
	/************************************************************************/
#pragma region TASK

#define		TIMER_THREAD				(1)			// 是否使用单独的thread做定时器
#define		TASK_POOL_TICKS_PER_SEC		(100)		// 声明1秒调度节拍数

#define		TASK_STATE_DEAD				(-1)
#define		TASK_STATE_IDLE				(0)
#define		TASK_STATE_RUN				(1)
	typedef enum class TaskPoolStateEnum
	{
		HALT = 1,
		RUN = 2,
		IDLE = 3,
		BUSY = 4
	} E_TaskPoolState;
	typedef enum class SignalStateEnum
	{
		IDLE = 1,
		POSTED = 2,
		PENDING = 3,
		TIMEOUT = 4
	} E_SignalState;
	typedef enum class TaskPrioriEnum
	{
		LOW = 1,
		NORMAL = 2,
		HIGH = 3
	}E_TaskPriori;

	class TaskPool;
	class Task
	{
	public:
		Task(std::function <void(void)> func, E_TaskPriori priori, int64_t period_ms)
		{
			this->priori = priori;
			taskFunc = func;
			if (period_ms >= 0)
			{
				period = period_ms * TASK_POOL_TICKS_PER_SEC / 1000;
				delayCnt = period;
			}
			else
			{
				period = -1;
				delayCnt = -1;
			}
			state = TASK_STATE_IDLE;
		}

	protected:
		E_TaskPriori	priori;
		int32_t			state;
		int64_t			period;
		int64_t			delayCnt;
		std::function <void(void)> taskFunc;

		friend class TaskPool;
	};
	class Signal
	{
	public:
		Signal(Task * pend_tsk)
		{
			state = E_SignalState::IDLE;
			pendTask = pend_tsk;
			timeOutClk = -1;
			sigCount = 0;
		}

		void Post()
		{
			sigCount++;
			state = E_SignalState::POSTED;
		}
		bool Pend(uint64_t time_out_ms)
		{
			if (sigCount > 0)
			{
				sigCount--;
				state = E_SignalState::IDLE;
				return true;
			}

			if (state == E_SignalState::IDLE)
			{
				timeOutClk = time_out_ms * TASK_POOL_TICKS_PER_SEC / 1000;;
				state = E_SignalState::PENDING;
			}
			return false;
		}

	protected:
		int64_t timeOutClk;
		Task * pendTask;
		int64_t sigCount;
		E_SignalState state;

		friend class TaskPool;
	};

	class TaskPool
	{
	public:
		TaskPool();
		~TaskPool();

		// period_ms = 0 : wake up every clk
		// period_ms = -1: not period, only waked up by signal
		Task * AddTask(std::function <void(void)> func, E_TaskPriori priori, int64_t period_ms = -1)
		{
			Task * task = new Task(func, priori, period_ms);
			switch (priori)
			{
			case E_TaskPriori::LOW:lowTasks.push_back(task); break;
			case E_TaskPriori::NORMAL:normalTasks.push_back(task); break;
			case E_TaskPriori::HIGH:highTasks.push_back(task); break;
			default:break;
			}

			return task;
		}
		Signal * AddSignal(Task * pend_tsk)
		{
			Signal * sig = new Signal(pend_tsk);
			signals.push_back(sig);
			return sig;
		}

		void Start()
		{
			init();
			while (1)
			{
				tasksSchedule();
			}
		}
		void TickIsr()
		{
			runTicCnt++;

			slicesTicCnt++;
			if (state == E_TaskPoolState::BUSY)
				busyTicCnt++;

			for (Task * task : highTasks)
			{
				if (task->state == TASK_STATE_DEAD)
					continue;

				if (task->delayCnt > 0)
					task->delayCnt--;

				if (task->delayCnt == 0)
				{
					task->state++;
					task->delayCnt = task->period;
				}
			}
			for (Task * task : normalTasks)
			{
				if (task->state == TASK_STATE_DEAD)
					continue;

				if (task->delayCnt > 0)
					task->delayCnt--;

				if (task->delayCnt == 0)
				{
					task->state++;
					task->delayCnt = task->period;
				}
			}
			for (Task * task : lowTasks)
			{
				if (task->state == TASK_STATE_DEAD)
					continue;

				if (task->delayCnt > 0)
					task->delayCnt--;

				if (task->delayCnt == 0)
				{
					task->state++;
					task->delayCnt = task->period;
				}
			}

			for (Signal * sig : signals)
			{
				if (sig->timeOutClk > 0)
					sig->timeOutClk--;

				// time out, do the pending task
				if (sig->state == E_SignalState::PENDING)
				{
					if (sig->timeOutClk == 0)
					{
						sig->pendTask->state++;
						sig->state = E_SignalState::TIMEOUT;
					}
				}

				// wake up no-period task
				if (sig->state == E_SignalState::POSTED)
				{
					if (sig->pendTask->delayCnt < 0)
					{
						sig->pendTask->state++;
						sig->state = E_SignalState::IDLE;
					}
				}
			}
		}

		size_t TaskNum() { return highTasks.size() + normalTasks.size() + lowTasks.size(); }
		double Usage() { return usage; }
		uint64_t RunTicks() { return runTicCnt; }

	protected:
		void init();
		void release();
		void tasksSchedule()
		{
			for (Task * task : highTasks)
			{
				if (task->state > 0)
				{
					state = E_TaskPoolState::BUSY;
					task->taskFunc();
					task->state--;
					state = E_TaskPoolState::IDLE;
					return;
				}
			}
			for (Task * task : normalTasks)
			{
				if (task->state > 0)
				{
					state = E_TaskPoolState::BUSY;
					task->taskFunc();
					task->state--;
					state = E_TaskPoolState::IDLE;
					return;
				}
			}
			for (Task * task : lowTasks)
			{
				if (task->state > 0)
				{
					state = E_TaskPoolState::BUSY;
					task->taskFunc();
					task->state--;
					state = E_TaskPoolState::IDLE;
					return;
				}
			}
			idleTask();
		}
		void idleTask()
		{
			if (slicesTicCnt >= 100)
			{
				usage = 1.0 * busyTicCnt / slicesTicCnt;
				busyTicCnt = 0;
				slicesTicCnt = 0;
			}
			//LOG("run tic = %lld, slices tic = %d, busy tic = %d, usage = %.4f.", runTicCnt, slicesTicCnt, busyTicCnt, usage);
		}

		std::vector<Task*> lowTasks;
		std::vector<Task*> normalTasks;
		std::vector<Task*> highTasks;
		std::vector<Signal*> signals;

		E_TaskPoolState	state;
		uint64_t		runTicCnt; // 运行总时长

		// 用于任务池使用率计算	
		double		usage;
		uint32_t	slicesTicCnt;
		uint32_t	busyTicCnt;
	};
	
	//////////////////////////////////////////////////////////////////////////////////////////////////////////
	extern void RunTaskPoolTest();

#pragma endregion

	/************************************************************************/
	/* thread																*/
	/************************************************************************/
#pragma region THREAD
	typedef void* Event;
	typedef void* Mutex;
	typedef void* Semaph;
	typedef int64_t Thread;
#ifdef _WIN32
#define THREAD_CALL void
	typedef void (*ThreadEntry)(void*);
#else
#define THREAD_CALL void*
	typedef void *(ThreadEntry)(void*);
#endif
#ifndef INFINITE
#define INFINITE -1
#endif

	Thread ThreadCreate(ThreadEntry entry_function, void* entry_argument = nullptr, uint32_t stack_size = 0);
	void ThreadDestory(Thread thread);
	bool ThreadWaitFor(Thread thread);
	bool ThreadsWaitForAll(Thread* threads, uint32_t thread_count);

	Mutex MutexCreate();
	void MutexDestroy(Mutex lock);
	bool MutexTryLock(Mutex lock);	// thread won't be blocked. true = success
	bool MutexLock(Mutex lock);		// thread will be blocked until mutex is locked (unlocked by other thread). true = success
	void MutexUnlock(Mutex lock);
	
	Event EventCreate(bool auto_reset = true, bool init_state = false); // init_state = true: event is set after created
	void EventDestroy(Event event);
	bool EventSet(Event event);
	bool EventReset(Event event);
	bool EventWaitFor(Event event, int msec = INFINITE);   // msec = 0: return immediately; msec = INFINITE: return until wait event;
																	// return true: wait signal; return false: timeout or failed

	Semaph SemaphCreate(uint32_t init_cnt = 0, uint32_t max_cnt = 1); 
	void SemaphDestroy(Semaph sam);
	bool SemaphPost(Semaph sam, long cnt, long* pre_cnt = nullptr);
	bool SemaphPend(Semaph sam, int msec = INFINITE);		// msec = 0: return immediately; msec = INFINITE: return until wait event;
																	// return true: wait signal; return false: timeout or failed
#pragma endregion
}

#ifdef FF_UTILS_EN_CUDA
#ifdef FF_UTILS_EN_NVCC
#include "ff_utils_cuda.cuh"
#else
#include "ff_utils_cuda.h"
#endif
#endif

#ifdef FF_UTILS_EN_OCL
#include "ff_utils_ocl.h"
#endif

#ifdef FF_UTILS_EN_WINDOW
#include "ff_utils_window.h"
#endif

#ifdef FF_UTILS_EN_D3D
#include "ff_utils_d3d.h"
#include "ff_utils_window.h"
#endif

#ifdef FF_UTILS_EN_OGL
#include "ff_utils_ogl.h"
#endif
